package com.my.study.pool;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;

/**
 * @author Carlos
 * @version 1.0
 * @Description TODO
 * @date 2021/6/14 9:32
 **/
@Slf4j(topic = "c.TestForkJoin")
public class TestForkJoin {

    public static void main(String[] args) {
        ForkJoinPool pool = new ForkJoinPool(4);
//        Integer invoke = pool.invoke(new MyTask(5));
//        System.out.println(invoke);

        Integer invoke = pool.invoke(new MyTaskImprove(1, 5));
        System.out.println(invoke);

    }

}

@Slf4j(topic = "c.MyTask")
class MyTask extends RecursiveTask<Integer> {

    private int n;

    public MyTask(int n) {
        this.n = n;
    }

    @Override
    protected Integer compute() {
        if (n == 1) {
            log.debug("join() {}", n);
            return 1;
        }
        // 拆解任务
        MyTask task = new MyTask(n - 1);
        // 让一个新线程去执行此任务
        task.fork();
        log.debug("fork() {} + {}", n, task);

        int result = n + task.join();
        log.debug("join() {} + {} = {}", n, task, result);
        return result;
    }

    @Override
    public String toString() {
        return "{" + n + "}";
    }
}

/**
 * 优化任务的拆分
 */
@Slf4j(topic = "c.MyTaskImprove")
class MyTaskImprove extends RecursiveTask<Integer> {

    private int begin;
    private int end;

    public MyTaskImprove(int begin, int end) {
        this.begin = begin;
        this.end = end;
    }


    @Override
    protected Integer compute() {
        if (begin == end) {
            log.debug("join() {}", begin);
            return begin;
        }
        if (end - begin == 1) {
            log.debug("join() {} + {} = {}", begin, end, begin + end);
            return begin + end;
        }

        int mid = (begin + end) / 2;

        MyTaskImprove improve1 = new MyTaskImprove(begin, mid);
        // 让新线程去执行
        improve1.fork();

        MyTaskImprove improve2 = new MyTaskImprove(mid + 1, end);
        // 让新线程去执行
        improve2.fork();

        log.debug("fork() {} + {} = ?", improve1, improve2);

        int result = improve1.join() + improve2.join();
        log.debug("join() {} + {} = {}", improve1, improve2, result);
        return result;
    }

    @Override
    public String toString() {
        return "{" +
                "begin=" + begin +
                ", end=" + end +
                '}';
    }
}
